//------------------------------------------------------------------------------
//
// Generic Brick Service State
//
// Written Jan-2008 by Trevor Taylor, Software Technology, Australia
//
// IMPORTANT NOTE:
// See the information in GenericBrickState.cs
//
//------------------------------------------------------------------------------

using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using System;
using System.Collections.Generic;
using W3C.Soap;
using genericbrick = ProMRDS.Robotics.GenericBrick;

// This is required for some of the attributes
using System.ComponentModel;

namespace ProMRDS.Robotics.GenericBrick
{
    #region State

    /// <summary>
    /// The GenericBrick State
    /// </summary>
    [DataContract]
    public partial class GenericBrickState
    {
        private string _name;
        private bool _connected;

        /// <summary>
        /// Brick Name
        /// </summary>
        /// <remarks>This is set by the service and not read from the Brick</remarks>
        [DataMember, Description("Friendly name for the Brick")]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Firmware Details (optional)
        /// </summary>
        /// <remarks>This information is read from the Brick</remarks>
        [DataMember, Description("Firmware information")]
        [Browsable(false)]
        public Firmware Firmware;

        /// <summary>
        /// Communications Configuration
        /// </summary>
        /// <remarks>This information should be read from the config file</remarks>
        [DataMember, Description("Communications Configuration")]
        public CommsConfig Configuration;

        /// <summary>
        /// Connection Flag
        /// </summary>
        [DataMember, Description("Indicates if a connection to the Brick is established")]
        [Browsable(false)]
        public bool Connected
        {
            get { return _connected; }
            set { _connected = value; }
        }

        /// <summary>
        /// Communications Statistics (optional)
        /// </summary>
        [DataMember, Description("Holds the statistics for the communications link (optional)")]
        [Browsable(false)]
        public CommsStats CommsStats;

        /// <summary>
        /// Summary of the Capabilities of the Brick
        /// </summary>
        /// <remarks>This should NOT be determined from the config file</remarks>
        [DataMember, Description("Brick Capabilities Bitmask")]
        public BrickCapabilities Capabilities;

        /// <summary>
        /// Brick Sensors (Inputs)
        /// </summary>
        [DataMember, Description("All Inputs (Digital and Analog)")]
        [Browsable(false)]
        public List<Device> Sensors;

        /// <summary>
        /// Brick Actuators (Outputs)
        /// </summary>
        [DataMember, Description("All Outputs (Digital and Analog)")]
        [Browsable(false)]
        public List<Device> Actuators;
        
        /// <summary>
        /// Status of LEDs (optional -- can use Actuators instead)
        /// </summary>
        /// <remarks>NOTE: LEDs are also listed as Actuators</remarks>
        [DataMember, Description("LED settings as a binary Bitmask")]
        [Browsable(false)]
        public int LEDs;

        /// <summary>
        /// Status of Switches (optional -- can use Sensors instead)
        /// </summary>
        /// <remarks>NOTE: Switches are also listed as Sensors</remarks>
        [DataMember, Description("Switch Status as a binary Bitmask")]
        [Browsable(false)]
        public int Switches;

        /// <summary>
        /// Drive Power (optional)
        /// </summary>
        [DataMember, Description("Specifies the current Drive Power settings")]
        [Browsable(false)]
        public DrivePower DrivePower;

    }

    #endregion

    #region Classes inside State

    /// <summary>
    /// Generic Brick Firmware Version Information
    /// </summary>
    [DataContract]
    [Description("Information about the Brick Firmware (optional)")]
    public class Firmware
    {
        /// <summary>
        /// Brick Firmware Version
        /// </summary>
        /// <remarks>Only valid if the Brick returns version info as a string</remarks>
        /// NOTE: Implementors of Brick firmware should make sure that the
        /// version information is in the format of a string that ends with
        /// the version number as vv.nn (C format is %d.%d)
        /// where vv is the major version and nn is the minor version
        [DataMember, Description("Brick Firmware Version String (optional)")]
        [Browsable(false)]
        public string VersionString;

        /// <summary>
        /// Major Firmware Version
        /// </summary>
        /// <remarks>Obtained from the Brick (if possible)</remarks>
        [DataMember, Description("Major Version Number of Brick Firmware (optional)")]
        [Browsable(false)]
        public int MajorVersion;

        /// <summary>
        /// Minor Firmware Version
        /// </summary>
        /// <remarks>Obtained from the Brick (if possible)</remarks>
        [DataMember, Description("Minor Version Number of Brick Firmware (optional)")]
        [Browsable(false)]
        public int MinorVersion;
    }

    /// <summary>
    /// Communications Configuration Parameters
    /// </summary>
    /// NOTE: This class is used as the message type for ConfigureBrick
    /// therefore it should contain all of the configurable information.
    /// Perhaps it should not be just Comms properties.
    /// Also, you might prefer NOT to set some of these. For example, it
    /// is unlikely that another service would be able to set the baud rate.
    [DataContract]
    [DataMemberConstructor]
    [Description("Low-level Communications configuration parameters")]
    public class CommsConfig
    {
        private int _serialPort;
        private int _baudRate;
        private int _delay;
        private int _timeout;
        private int _pollingInterval;

        /// <summary>
        /// Communications Serial Port
        /// </summary>
        [DataMember, Description("Serial Port used to communicate with the robot's Brick")]
        public int SerialPort
        {
            get { return this._serialPort; }
            set { this._serialPort = value; }
        }

        /// <summary>
        /// Communications Baud Rate
        /// </summary>
        [DataMember, Description("Baud Rate for Serial Port (0 = default)")]
        public int BaudRate
        {
            get { return this._baudRate; }
            set { this._baudRate = value; }
        }

        // The following two parameters are implementation-specific
        // Delay sets the minimum amount of time between messages. This is needed
        // for some PICs because they are slow processing commands and will lose
        // commands if they are not ready. It might be 50 or 100 ms.
        // Timeout is the timeout set on the serial port in case an operation
        // does not complete. This is intended to catch broken connections
        // or failed commands.
        //
        [DataMember, Description("Delay (in ms) between messages to the serial port")]
        public int Delay
        {
            get { return this._delay; }
            set { this._delay = value; }
        }

        [DataMember, Description("Timeout (in ms) on serial port commands")]
        public int Timeout
        {
            get { return this._timeout; }
            set { this._timeout = value; }
        }

        /// <summary>
        /// Polling Interval (if required)
        /// </summary>
        [DataMember, Description("Polling Interval in milliseconds for reading sensors (if necessary)")]
        public int PollingInterval
        {
            get { return this._pollingInterval; }
            set { this._pollingInterval = value; }
        }

    }

    /// <summary>
    /// Communications Statistics (Optional)
    /// </summary>
    [DataContract]
    [Description("Statistics on the Communications Link (Optional)")]
    public class CommsStats
    {
        private int _messagesSent;
        private int _messagesReceived;
        private int _errorCount;

        [DataMember, Description("Records the count of messages sent to the robot")]
        [Browsable(false)]
        public int MessagesSent
        {
            get { return this._messagesSent; }
            set { this._messagesSent = value; }
        }

        [DataMember, Description("Records the count of messages received from the robot")]
        [Browsable(false)]
        public int MessagesReceived
        {
            get { return this._messagesReceived; }
            set { this._messagesReceived = value; }
        }

        [DataMember, Description("Records how many communication errors have occured")]
        [Browsable(false)]
        public int ErrorCount
        {
            get { return _errorCount; }
            set { _errorCount = value; }
        }

    }

    /// <summary>
    /// Drive Power
    /// </summary>
    /// NOTE: This class is used as the response type for QueryDrivePower.
    [DataContract]
    [DataMemberConstructor]
    [Description("Specifies the Drive Power (Left and Right Motors)")]
    public class DrivePower
    {
        private double _leftPower;
        private double _rightPower;

        [DataMember, DataMemberConstructor(Order = 1)]
        [Description("Left motor power setting")]
        public double LeftPower
        {
            get { return this._leftPower; }
            set { this._leftPower = value; }
        }

        [DataMember, DataMemberConstructor(Order = 2)]
        [Description("Right motor power setting")]
        public double RightPower
        {
            get { return this._rightPower; }
            set { this._rightPower = value; }
        }

    }

    #endregion

}
